package FolderOperation.main;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.text.PDFTextStripper;
import org.apache.poi.hwpf.HWPFDocument;
import jxl.Cell;
import jxl.Sheet;
import jxl.Workbook;
import jxl.read.biff.BiffException;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import java.io.*;
import java.math.BigInteger;
import java.security.MessageDigest;

/*
*1.文件夹整理小工具：将固定文件下的所有文件，以文件后缀分组建立子目录，
		○ 可输入关键字（8个字符以内），模糊匹配文件名和文件内容，返回文件路径
		○ 按文件相似度（相似文件名，文件生成日期，大小）去除重复文件；(相似度作为，可配置参数)
        ○ 支持的文件类型 *.txt,*.pdf,*.doc,*.docx,*.xls,*.xlsx）
 */
/*
 *class FolderOperation作为底层，实现对给定路径：
 *   1，判断是否为文件夹。说明：在构造函数种完成，若不是文件夹（已完成）public
 *   2，查询根目录（Path）下是否存在名为name的文件夹 private                   -贺
 *   3，在根目录中创建名为name的文件夹 private                               -贺
 *   4，更改file到新目录path下（已完成）private
 *   5，遍历目录并根据文件后缀创建文件夹 public（已完成，未测试）
 *   6，实现两个String的模糊匹配 private                                    -齐
 *   7，给定file与字符串str,先对比file.getName()与str，若模糊匹配则返回true,否则，读取内容（注意不同后缀QAQ），逐词模糊匹配。-齐
 *   8，两个文件的比较boolen （File,File）                                  -华
 *   9，遍历删除相同文件                                                   -郎
 *   10,到此为止，好像没啥要写的了。QAQ
 */
public class FolderOperation {
    private String Path;                    //根目录
    private File WorkingDirectory;          //根目录
    private File[] WorkingDirectoryList;    //根目录文件列表
    private MessageDigest mMessageDigest = null;
    private String supportType="txtpdfdocdocxxlsxlsxundefined";
    // 1
    public FolderOperation(String path) throws Exception{
        Path = path;
        WorkingDirectory=new File(path);
        if (!WorkingDirectory.isDirectory()){//判断path是否为文件夹
            throw new Exception(path+": inexistence or is not a directory!");
        }
        WorkingDirectoryList=WorkingDirectory.listFiles();//读取当前目录
        mMessageDigest = MessageDigest.getInstance("MD5");//初始化md5生成
        System.out.println(path+": find!");
    }
    // 2-查找当前目录下是否有名为name的文件夹
//    private boolean findDirectory(String name){
//        return true;
//    }
    // 3-在当前目录下创建名为name的文件夹 成功返回true 失败...
    private void makeDirectory(String name){
        File dir = new File(Path+"\\"+name);
        if (!dir.exists()) {// 判断目录是否存在
            dir.mkdir();
        }
    }
    // 4-更改file到新目录path下
    private void moveDirToNewPath(File file,String newPath){
        try{
            file.renameTo(new File(newPath+"\\"+file.getName()));
            file.delete(); //是否保留原文件  既然是整理文件，咱们这里就不保留了
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    // 5-遍历path目录，根据后缀分组创建文件夹（应该是已经完成了，但是前面的方法未完成，因此无法测试）
    private void divideByPostfix(File[] workingDirectoryList){
        //遍历WorkingDirectoryList
        for (File file:workingDirectoryList){
            //判断是否为文件
            if(file.isFile()){//是文件
                //截取后缀
                String postfix,wholeName= file.getName();
                String[] partName = wholeName.split("\\.");
                postfix=partName[partName.length-1];    //以最右边.后字符串为后缀
                if(partName.length<2){
                    //文件命名不规范
                    System.out.println("文件不规范");
                    postfix="undefined";
                }
                //根据后缀postfix，查询是否已经存在存在该文件夹
                makeDirectory(postfix);
                //移动文件
                moveDirToNewPath(file,Path+"\\"+postfix);
            }else{//是文件夹 （需要递归）
                divideByPostfix(file.listFiles());
                if(supportType.indexOf(file.getName())==-1) file.delete();//好像就是放在这里删除的。 大家也思考一下！QAQ 写完跑一下！！！
            }
        }
    }
//    //  6-模糊匹配字符串a b 相似返回true；
//    private boolean stringFuzzyMatch(String a,String b){//具体实现根”模糊“的定义实现
//        return true;
//    }
    // 7-给定file与字符串str,先对比file.getName()与str，若模糊匹配则返回true,否则，读取内容（注意不同后缀QAQ），逐词模糊匹配。
    //为了实现：当前文件是否含有字符串str,如果含有，返回ture，否则false
    private boolean findString(File file,String str){//
        String wholeName=file.getName();
        if(wholeName.indexOf(str)>-1) return true;
        //文件名无法匹配，则读取文件，逐词匹配内容（注意后缀，不同后缀打开方式不同，用switch吧）
        //根据后缀，调用不同方法判断。
        String[] partNames=wholeName.split("\\.");
        String postfix=partNames[partNames.length-1];
        if(postfix.equals("txt")) return txtFindString(file, str);
        if(postfix.equals("pdf")) return pdfFindString(file, str);
        if(postfix.equals("doc")) return docFindString(file, str);
        if(postfix.equals("docx")) return docxFindString(file, str);
        if(postfix.equals("xls")) return xlsFindString(file, str);
        if(postfix.equals("xlsx")) return xlsxFindString(file, str);
        System.out.println("不支持的文件类型");
        return false;
    }
    // 7-1 .txt -郎 数据流读取
    private boolean txtFindString(File file,String str){
        try {
            FileInputStream fis = new FileInputStream(file);
            InputStreamReader isr=new InputStreamReader(fis,"UTF-8");
            BufferedReader br=new BufferedReader(isr);
            String tempLine;
            while((tempLine=br.readLine())!=null){
                if(tempLine.indexOf(str)!=-1) return true;
            }
            br.close();
            isr.close();
            fis.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            System.out.println(file.getName()+"读取失败");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            System.out.println(file.getName()+"以UTF-8转码异常");
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println(file.getName()+"文件输出异常");
        }
        return false;
    }
    // 7-2 .pdf -郎 使用pdfbox
    private boolean pdfFindString(File file,String str){
        String textString = "";
        //SavePdfDocument pdfDocument = new SavePdfDocument();
        try {
//            PDDocument document = PDDocument.load(file);
            PDDocument document = Loader.loadPDF(file);
            //将提取出来的字节流转换为字符流进行显示
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            OutputStreamWriter writer = new OutputStreamWriter(out);
            getTextStripper(document, writer);
            document.close();
            out.close();
            writer.close();
            byte[] con = out.toByteArray();
            textString = new String(con);
            if(textString.indexOf(str)>-1) return true;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NoClassDefFoundError e){
            e.printStackTrace();
        }
        return false;
    }
    private void getTextStripper(PDDocument document, Writer writer)
            throws IOException {
        PDFTextStripper textStripper = new PDFTextStripper();
        textStripper.writeText(document, writer);
    }
    // 7-3 .doc
    private boolean docFindString(File file, String str) {
        String fileName = file.getName();
        String fileContent;
        if (isSubString(fileName, str)) return true;
        else {
            FileInputStream fis = null;
            try {
                fis = new FileInputStream(file);
                HWPFDocument doc = new HWPFDocument(fis);
                fileContent = doc.getDocumentText();
                fis.close();
                if (isSubString(fileContent, str)) return true;
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return false;
        }

    }
    // 7-4 .docx
    private boolean docxFindString(File file, String str){
        String fileName = file.getName();
        String fileContent;
        if (isSubString(fileName, str)) return true;
        else {
            try {
                FileInputStream fis = null;
                fis = new FileInputStream(file);
                XWPFDocument docx = new XWPFDocument(fis);
                XWPFWordExtractor xwpfWordExtractor = new XWPFWordExtractor(docx);
                fileContent = xwpfWordExtractor.getText();
                fis.close();
                if (isSubString(fileContent, str)) return true;//文档含有str->true
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return false;
        }

    }
    private boolean isSubString(String a, String b) {
        int intIndex = a.indexOf(b);//b是否是a的子串
        return intIndex != -1;
    }
    // 7-5 .xls -贺
    private boolean xlsFindString(File file, String str) {
        File f = file;
        try {
            Workbook book=Workbook.getWorkbook(f);//
            Sheet sheet=book.getSheet(0); //获得第一个工作表对象
            for(int i=0;i<sheet.getRows();i++){
                for(int j=0;j<sheet.getColumns();j++){
                    Cell cell=sheet.getCell(j, i); //获得单元格
                    if(cell.getContents().indexOf(str)>-1){
                        return true;
                    }
                }
            }
        } catch (BiffException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return false;
    }
    // 7-6 .xlsx
    private boolean xlsxFindString(File file,String str){
        FileInputStream fileInputStream = null;
        try {
            fileInputStream = new FileInputStream(file);
            XSSFWorkbook sheets = new XSSFWorkbook(fileInputStream);
            XSSFSheet sheet = sheets.getSheet("Sheet1");
            //获取行数
            int rows = sheet.getPhysicalNumberOfRows();
            for(int i=0;i<rows;i++){
                //获取列数
                XSSFRow row = sheet.getRow(i);
                int columns = row.getPhysicalNumberOfCells();
                for(int j=0;j<columns;j++){
                    String cell = row.getCell(j).toString();
                    if (cell.indexOf(str)>-1) return true;
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }
    // 8-比较两个文件是否相似 相似返回true 否则返回false
    private boolean fileCompare(File a,File b){//比较文件
        if (a.length()!=b.length()) return false;
        String amd5=getFileMD5String(a);
        String bmd5=getFileMD5String(b);
        if(amd5!=null && !amd5.equals(bmd5)) return false;
        return true;
    }
    // 8-1
    private String getFileMD5String(File file) {
        try {
            InputStream fis = new FileInputStream(file);
            byte[] buffer = new byte[1024];
            int length = -1;
            while ((length = fis.read(buffer, 0, 1024)) > 0) {
                mMessageDigest.update(buffer, 0, length);
            }
            fis.close();
            return new BigInteger(1, mMessageDigest.digest()).toString(16);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
//    private boolean isSubString(String a,String b){
//        System.out.print(a+" |<->| "+b);
//        int intIndex=a.indexOf(b);//b是否是a的子串
//        if(intIndex!=-1)
//            return true;
//        System.out.println(" |不匹配");
//        return false;
//    }
    // 9-清除同文件夹 -2
    public void deleteSameFile(File directory){
        File[] tempList = directory.listFiles();
        for (int i = 0;i< tempList.length;i++){
            if(tempList[i].isFile()){
                for(int j=i+1;j< tempList.length;j++){
                    if(tempList[j].isFile()){
                        if(fileCompare(tempList[i],tempList[j])){//比较文件
                            //System.out.println("是否删除"+tempList[j].getName()+",该文件与"+tempList[i].getName()+"相同。（y/n）:");
                            tempList[j].delete();
                        }
                    }
                }
                tempList=directory.listFiles();//在这里更新就可以了，反正j单向遍历一次，也不会遇到自己删除的文件。
            }
        }
    }
    // 10-整理文件夹 -3
    public void divideFolder(){
        WorkingDirectoryList=WorkingDirectory.listFiles();//读取当前目录
        divideByPostfix(WorkingDirectoryList);
    }
    // 11-寻找str -1
    public void findStr(String str){
        WorkingDirectoryList=WorkingDirectory.listFiles();//读取当前目录
        traverseFind(WorkingDirectoryList,str);
    }
    private void traverseFind(File[] fileList,String str){
        for (File aFile:fileList){
            if(aFile.isFile()){
                if(findString(aFile,str)) System.out.println(aFile.getPath());
            }else{
                traverseFind(aFile.listFiles(),str);
            }
        }
    }
}
